﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
using Telerik.Web.UI;

namespace mojoPortal.Web.RS.SBM.Components.Telerik.Template
{
    public partial class RadSchedulerAdvancedFormMultipleValuesResourceControl : System.Web.UI.UserControl
    {
        private string _type;

        /// <summary>
        /// A modified CheckBoxList that renders an unordered list, instead of a table.
        /// </summary>
        protected class SemanticCheckBoxList : CheckBoxList
        {
            protected override void Render(HtmlTextWriter writer)
            {
                writer.WriteBeginTag("ul");

                writer.WriteAttribute("class", "rsCheckBoxList");

                writer.Write(HtmlTextWriter.TagRightChar);

                for (int i = 0; i < RepeatedItemCount; i++)
                {
                    writer.RenderBeginTag(HtmlTextWriterTag.Li);
                    RenderItem(ListItemType.Item, i, null, writer);
                    writer.RenderEndTag();
                }

                writer.WriteEndTag("ul");
            }
        }

        protected Appointment Appointment
        {
            get
            {
                SchedulerFormContainer container = (SchedulerFormContainer)BindingContainer;
                return container.Appointment;
            }
        }

        protected RadScheduler Owner
        {
            get
            {
                return Appointment.Owner;
            }
        }

        protected SemanticCheckBoxList ResourceValue
        {
            get
            {
                return (SemanticCheckBoxList)FindControl("ResourceValue");
            }
        }

        [Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
        public object Value
        {
            get
            {
                return ExtractResourceValues();
            }

            set
            {

            }
        }

        [Bindable(BindableSupport.Yes, BindingDirection.OneWay)]
        public string Label
        {
            get
            {
                return ResourceLabel.Text.Trim();
            }

            set
            {
                ResourceLabel.Text = value;
            }
        }

        [Bindable(BindableSupport.Yes, BindingDirection.OneWay)]
        public string Type
        {
            get
            {
                return _type;
            }

            set
            {
                _type = value;
            }
        }


        protected void Page_Load(object sender, EventArgs e)
        {
            SemanticCheckBoxList resourceValue = new SemanticCheckBoxList();
            resourceValue.ID = "ResourceValue";
            ResourceValuesPlaceHolder.Controls.Add(resourceValue);

            if (resourceValue.Items.Count == 0)
            {
                PopulateResources();
                MarkSelectedResources();
            }
        }

        /// <summary>
        /// Populates the resource options.
        /// </summary>
        private void PopulateResources()
        {
            foreach (Resource res in GetResources(Type))
            {
                ResourceValue.Items.Add(new ListItem(res.Text, SerializeResourceKey(res.Key)));
            }
        }

        /// <summary>
        /// Marks (selects) the resources currently associated with the appointment.
        /// </summary>
        private void MarkSelectedResources()
        {
            foreach (Resource res in Appointment.Resources.GetResourcesByType(Type))
            {
                ResourceValue.Items.FindByValue(SerializeResourceKey(res.Key)).Selected = true;
            }
        }

        /// <summary>
        /// Gets a list of the resources of the specified type.
        /// </summary>
        /// <param name="resType">Type of the resources to search for.</param>
        /// <returns>A list of the resources of the specified type.</returns>
        private IEnumerable<Resource> GetResources(string resType)
        {
            List<Resource> availableResources = new List<Resource>();
            IEnumerable<Resource> resources = Owner.Resources.GetResourcesByType(resType);

            foreach (Resource res in resources)
            {
                if (IncludeResource(res))
                {
                    availableResources.Add(res);
                }
            }

            return availableResources;
        }

        /// <summary>
        /// Returns a boolean value, indicating if a resource should be included in the list.
        /// You can use this method to define your custom filtering logic.
        /// </summary>
        /// <param name="res">The resource to filter.</param>
        /// <returns>A boolean value, indicating if a resource should be included in the list.</returns>
        private bool IncludeResource(Resource res)
        {
            return res.Available || ResourceIsInUse(res);
        }

        /// <summary>
        /// Returns a boolean value, indicating if a resource is already assigned to the appointment.
        /// </summary>
        /// <param name="res">The resource to check.</param>
        /// <returns>A boolean value, indicating if a resource is already assigned to the appointment.</returns>
        private bool ResourceIsInUse(Resource res)
        {
            foreach (Resource appRes in Appointment.Resources)
            {
                if (res == appRes)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Extracts the resource values from the CheckBoxList.
        /// </summary>
        /// <returns>
        /// Depending the number of selected resources it returns either
        /// a single key or an array of resource keys.
        /// </returns>
        private object ExtractResourceValues()
        {
            ArrayList resourceKeys = new ArrayList();
            foreach (ListItem li in ResourceValue.Items)
            {
                if (li.Selected && li.Value != "NULL")
                {
                    resourceKeys.Add(DeserializeResourceKey(li.Value));
                }
            }

            switch (resourceKeys.Count)
            {
                case 0:
                    return string.Empty;

                case 1:
                    return resourceKeys[0];

                default:
                    return resourceKeys.ToArray();
            }
        }

        /// <summary>
        /// Serializes a resource key using LosFormatter.
        /// </summary>
        /// <remarks>
        ///	The resource keys need to be serialized as they can be arbitrary objects.
        /// </remarks>
        /// <param name="key">The key to serialize.</param>
        /// <returns>The serialized key.</returns>
        private string SerializeResourceKey(object key)
        {
            LosFormatter output = new LosFormatter();
            StringWriter writer = new StringWriter();
            output.Serialize(writer, key);
            return writer.ToString();
        }

        /// <summary>
        /// Deserializes a resource key using LosFormatter.
        /// </summary>
        /// <remarks>
        ///	The resource keys need to be serialized as they can be arbitrary objects.
        /// </remarks>
        /// <param name="key">The key to deserialize.</param>
        /// <returns>The deserialized key.</returns>
        private object DeserializeResourceKey(string key)
        {
            LosFormatter input = new LosFormatter();
            return input.Deserialize(key);
        }
    }
}